Skip to content

fix(codex): handle remote request_user_input approvals#382

Open
lwc-alex wants to merge 1 commit intotiann:mainfrom
lwc-alex:codex/fix-remote-request-user-input
Open

fix(codex): handle remote request_user_input approvals#382
lwc-alex wants to merge 1 commit intotiann:mainfrom
lwc-alex:codex/fix-remote-request-user-input

Conversation

@lwc-alex
Copy link
Copy Markdown

@lwc-alex lwc-alex commented Apr 1, 2026

Fix remote Codex sessions hanging/canceling on request_user_input tool approvals.

Root cause:

  • codexRemoteLauncher registers app-server permission handlers without onUserInputRequest
  • appServerPermissionAdapter falls back to cancel for item/tool/requestUserInput

This patch wires request_user_input into the existing Codex remote permission flow and adds focused tests.

Validated with:

  • bun x vitest run src/codex/utils/permissionHandler.test.ts src/codex/utils/appServerPermissionAdapter.test.ts src/codex/codexRemoteLauncher.test.ts
  • bun run typecheck

Copy link
Copy Markdown

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

  • [Major] Explicit deny for request_user_input is downgraded to cancel. handleUserInputRequest() rejects the non-accept path, and this launcher catch always returns { decision: 'cancel' }, so Telegram or any generic denyPermission() caller can never propagate decline back to Codex. The same path also records the completed request as canceled instead of denied in cli/src/codex/utils/permissionHandler.ts. This changes user-visible behavior for deny actions instead of only fixing the hang. Evidence: cli/src/codex/codexRemoteLauncher.ts:519, cli/src/codex/utils/permissionHandler.ts:168, hub/src/telegram/callbacks.ts:90.
    Suggested fix:
    type UserInputApproval =
        | { decision: 'accept'; answers: RequestUserInputAnswers }
        | { decision: 'decline' | 'cancel'; reason?: string }
    
    const result = await permissionHandler.handleUserInputRequest(id, input)
    return result.decision === 'accept'
        ? result
        : { decision: result.decision }

Summary

  • Review mode: initial
  • 1 major finding. Main risk is that explicit deny paths for remote request_user_input prompts no longer behave like deny; they are collapsed into cancel/abort semantics instead.

Testing

  • Not run (automation environment missing bun; bun x vitest ... and bun run typecheck both failed with /bin/bash: bun: command not found)

HAPI Bot

const message = error instanceof Error ? error.message : String(error);
logger.debug(`[Codex] request_user_input failed: ${message}`);
return {
decision: 'cancel'
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MAJOR] Explicit deny is being collapsed to cancel here. handleUserInputRequest() rejects every non-accept outcome, and this catch hard-codes { decision: 'cancel' }, so Telegram or any other denyPermission() caller never returns decline to Codex. The same path is then finalized as canceled instead of denied in cli/src/codex/utils/permissionHandler.ts:168, which changes the behavior of real deny actions rather than only fixing the hang.

Suggested fix:

type UserInputApproval =
    | { decision: 'accept'; answers: RequestUserInputAnswers }
    | { decision: 'decline' | 'cancel'; reason?: string }

const result = await permissionHandler.handleUserInputRequest(id, input)
return result.decision === 'accept'
    ? result
    : { decision: result.decision }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant